package com.demo.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.CharsetUtil;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;


/**
 * @author gy
 * @date 2022/5/30
 * 1、我们自定义一个Handler，需要继承 netty 规定好的 某个 HandlerAdapter（规范）
 * 2、这时我们自定义一个Handler，才能称为一个 handler
 *
 * 非当前 Reactor 线程调用 Channel 的各种方法
 *   例如在推送系统的业务线程里面，根据用户的标识，找到对应的 Channel引用，
 *   然后调用 Write类方法向该用户推送消息，就会进入到这种场景。最终的Write会提交到
 *   任务队列中后被异步消费
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 读取数据 实际（这里我们可以读取客户端发送的消息）
     * @param ctx 上下文对象，含有 管道 pipeLine，通道channel，地址
     * @param msg 就是客户端发送的数据，默认为 object
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 比如我们这里有一个非常耗时长的业务 -> 异步执行 -> 提交该 channel 对应的
        // NIOEventLoop 的 taskQueue中，

        /**
         * 解决方案1 用户程序自定义的普通任务
         */
        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~ 222",CharsetUtil.UTF_8));
                } catch (Exception e) {
                    System.out.println("发生异常" + e);
                }
            }
        });
        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    // 注意：此条数据 会在 30 后才能发送成功，因为和上方的任务 均属于同一个线程
                    Thread.sleep(20 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~ 333",CharsetUtil.UTF_8));
                } catch (Exception e) {
                    System.out.println("发生异常" + e);
                }
            }
        });

        /**
         * 2、用户自定义定时任务 -> 该任务是提交到  scheduleTaskQueue中
         */
        ctx.channel().eventLoop().schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    // 注意：此条数据 会在 30 后才能发送成功，因为和上方的任务 均属于同一个线程
                    Thread.sleep(20 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~ 444",CharsetUtil.UTF_8));
                } catch (Exception e) {
                    System.out.println("发生异常" + e);
                }
            }
        },5, TimeUnit.SECONDS);

        System.out.println("go on ...");







//        System.out.println("服务器读取线程 " + Thread.currentThread().getName());
//        System.out.println("server ctx = " + ctx);
//        System.out.println("看看 channel 和 pipeline的 关系");
//        Channel channel = ctx.channel();
//        // 本质是一个双向链表，出栈、入栈的问题
//        ChannelPipeline pipeline = ctx.pipeline();
//        // 将 msg 转成一个 ByteBuf
//        // ByteBuf 是 Netty 提供的，不是 NIO 的 ByteBuffer
//        ByteBuf buf = (ByteBuf)msg;
//        System.out.println("客户端发送消息是：" + buf.toString(CharsetUtil.UTF_8));
//        System.out.println("客户端地址：" + channel.remoteAddress());
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        /**
         * 1、writeAndFlush 是 write + flush
         * 2、将数据写入到缓存，并刷新
         * 3、一般讲，我们对这个发送的数据进行编码
         */
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~ 111",CharsetUtil.UTF_8));
    }

    /**
     * 处理异常，一般是需要关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
